using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
using System;
using System.IO;
using System.Text;
using System.Linq;
using System.Security.Claims;
using UniversalAdmin.Domain.Entities.App;
using UniversalAdmin.Infrastructure.Data.Contexts;
using System.Diagnostics;

namespace UniversalAdmin.Api.Middleware
{
    public class OperationLogMiddleware
    {
        private readonly RequestDelegate _next;

        public OperationLogMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        // 获取真实客户端IP地址
        private string GetClientIpAddress(HttpContext context)
        {
            // 尝试从各种头部获取真实IP
            var ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault()?.Split(',')[0]?.Trim();
            if (!string.IsNullOrEmpty(ip) && ip != "unknown")
                return ip;

            ip = context.Request.Headers["X-Real-IP"].FirstOrDefault();
            if (!string.IsNullOrEmpty(ip))
                return ip;

            ip = context.Request.Headers["X-Client-IP"].FirstOrDefault();
            if (!string.IsNullOrEmpty(ip))
                return ip;

            ip = context.Request.Headers["CF-Connecting-IP"].FirstOrDefault();
            if (!string.IsNullOrEmpty(ip))
                return ip;

            // 获取连接IP，优先IPv4
            var remoteIp = context.Connection.RemoteIpAddress;
            if (remoteIp != null)
            {
                // 如果是IPv6映射的IPv4地址，转换为IPv4
                if (remoteIp.IsIPv4MappedToIPv6)
                {
                    return remoteIp.MapToIPv4().ToString();
                }
                // 如果是IPv6本地回环，返回IPv4的localhost
                else if (remoteIp.ToString() == "::1")
                {
                    return "127.0.0.1";
                }
                else
                {
                    return remoteIp.ToString();
                }
            }
            
            return "unknown";
        }

        public async Task InvokeAsync(HttpContext context, AdminDbContext dbContext)
        {
            var stopwatch = Stopwatch.StartNew();
            AppOperationLog? log = null;
            
            try
            {
                // 只记录已登录用户的业务API请求，排除静态资源和查看日志
                if (context.User?.Identity?.IsAuthenticated == true &&
                    context.Request.Path.StartsWithSegments("/api", StringComparison.OrdinalIgnoreCase) &&
                    !context.Request.Path.StartsWithSegments("/api/static", StringComparison.OrdinalIgnoreCase) &&
                    !context.Request.Path.StartsWithSegments("/api/system/logs", StringComparison.OrdinalIgnoreCase) && // 排除系统日志查看
                    !context.Request.Path.StartsWithSegments("/api/files/preview", StringComparison.OrdinalIgnoreCase) && // 排除文件预览
                    !context.Request.Path.StartsWithSegments("/api/users/avatar", StringComparison.OrdinalIgnoreCase)) // 排除头像预览
                {
                    var userIdStr = context.User.FindFirst("UserId")?.Value;
                    Guid.TryParse(userIdStr, out Guid userId);

                    // 获取请求信息
                    string requestBody = "";
                    if (context.Request.ContentLength > 0 && context.Request.Body.CanSeek)
                    {
                        context.Request.Body.Position = 0;
                        using (var reader = new StreamReader(context.Request.Body, Encoding.UTF8, true, 1024, true))
                        {
                            requestBody = await reader.ReadToEndAsync();
                            context.Request.Body.Position = 0;
                        }
                    }

                    // 获取查询参数
                    string queryString = context.Request.QueryString.HasValue ? context.Request.QueryString.Value : "";

                    // 确定日志级别和模块
                    string logLevel = "info";
                    string module = GetModuleFromPath(context.Request.Path);
                    string message = GetMessageFromOperation(context.Request.Method, context.Request.Path);

                    // 添加调试信息
                    Console.WriteLine($"记录日志: Module={module}, Message={message}, LogLevel={logLevel}");

                    // 记录请求开始
                    log = new AppOperationLog
                    {
                        Id = Guid.NewGuid(),
                        UserId = userId,
                        Action = queryString,
                        Operation = $"{context.Request.Method} {context.Request.Path}",
                        Resource = "System",
                        ResourceId = null,
                        IpAddress = GetClientIpAddress(context),
                        UserAgent = context.Request.Headers["User-Agent"].ToString() ?? "",
                        LogLevel = logLevel,
                        Module = module,
                        Message = message,
                        RequestBody = requestBody,
                        Details = null,
                        Exception = null,
                        ResponseBody = null,
                        StatusCode = null,
                        ExecutionTime = null,
                        CreatedAt = DateTime.UtcNow
                    };

                    Console.WriteLine($"创建日志记录: {log.Id}, Module={log.Module}, Message={log.Message}");

                    dbContext.AppOperationLogs.Add(log);
                    await dbContext.SaveChangesAsync();

                    Console.WriteLine($"日志记录已保存: {log.Id}");

                    // 继续处理请求
                    await _next(context);

                    // 记录响应信息
                    stopwatch.Stop();
                    
                    Console.WriteLine($"请求完成，耗时: {stopwatch.ElapsedMilliseconds}ms, 状态码: {context.Response.StatusCode}");
                    
                    // 重新查询日志记录以更新
                    var existingLog = await dbContext.AppOperationLogs.FindAsync(log.Id);
                    if (existingLog != null)
                    {
                        existingLog.ExecutionTime = stopwatch.ElapsedMilliseconds;
                        existingLog.StatusCode = context.Response.StatusCode;

                        // 根据状态码调整日志级别
                        if (context.Response.StatusCode >= 400)
                        {
                            existingLog.LogLevel = context.Response.StatusCode >= 500 ? "error" : "warn";
                            existingLog.Message = $"请求失败 - {context.Response.StatusCode}";
                        }
                        else
                        {
                            existingLog.Message = $"请求成功 - {context.Response.StatusCode}";
                        }

                        await dbContext.SaveChangesAsync();
                        Console.WriteLine($"日志记录已更新: {existingLog.Id}");
                    }
                    else
                    {
                        Console.WriteLine($"未找到日志记录: {log.Id}");
                    }
                }
                else
                {
                    await _next(context);
                }
            }
            catch (Exception ex)
            {
                stopwatch.Stop();
                
                // 记录异常日志
                if (context.User?.Identity?.IsAuthenticated == true)
                {
                    var userIdStr = context.User.FindFirst("UserId")?.Value;
                    Guid.TryParse(userIdStr, out Guid userId);

                    var errorLog = new AppOperationLog
                    {
                        Id = Guid.NewGuid(),
                        UserId = userId,
                        Action = "",
                        Operation = $"{context.Request.Method} {context.Request.Path}",
                        Resource = "System",
                        ResourceId = null,
                        IpAddress = GetClientIpAddress(context),
                        UserAgent = context.Request.Headers["User-Agent"].ToString() ?? "",
                        LogLevel = "error",
                        Module = GetModuleFromPath(context.Request.Path),
                        Message = $"系统异常: {ex.Message}",
                        Exception = ex.ToString(),
                        ExecutionTime = stopwatch.ElapsedMilliseconds,
                        StatusCode = 500,
                        Details = null,
                        RequestBody = null,
                        ResponseBody = null,
                        CreatedAt = DateTime.UtcNow
                    };

                    dbContext.AppOperationLogs.Add(errorLog);
                    await dbContext.SaveChangesAsync();
                }

                throw;
            }
        }

        private string GetModuleFromPath(PathString path)
        {
            var segments = path.Value?.Split('/', StringSplitOptions.RemoveEmptyEntries);
            if (segments != null && segments.Length > 1)
            {
                return segments[1].ToUpperInvariant(); // 取第二个段作为模块名
            }
            return "SYSTEM";
        }

        private string GetMessageFromOperation(string method, PathString path)
        {
            var segments = path.Value?.Split('/', StringSplitOptions.RemoveEmptyEntries);
            if (segments != null && segments.Length > 1)
            {
                var module = segments[1];
                var action = segments.Length > 2 ? segments[2] : "";
                
                return $"{method.ToUpperInvariant()} {module} {action}".Trim();
            }
            return $"{method.ToUpperInvariant()} {path}";
        }
    }
} 